﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;

using YEngineLib;
using YEngineLib.Graphics;
using YEngineLib.Input;
using YEngineLib.State;
using YEngineLib.Util;


using System.Threading;
using Spyfall.Objects;
using Spyfall.Managers;
using Spyfall.Messages;

using System.IO;

namespace Spyfall.States
{
    class GameState : YBaseGameState
    {
        //private ParallaxBackground bgLayer1;
        //private Obstacles obstacleStuff;
        private City cityLayer1;
        private AltitudeTimerClass HUD;
        private Managers.ObjectManager objectManager;

        //private PausedScreenExit pauseScreenExit;
        //private PauseScreenMain pauseScreenMainSelected;
        //private PauseScreenResume pauseScreenResume;
        bool howToPlay;
        bool paused;
        int pausedMenu = 1;
        public Texture2D[] cloudArray = new Texture2D[5];
        public Vector2[] cloudArrayPos = new Vector2[5];
        public int[] cloudArrayVelo = new int[5];
        public int powerCounter;
        public float timer;
        Player MyLittlePlayer;
        Enemy MyLittleEnemy;

        public ShopState buff;

        // Gamepad states used to determine button presses
        GamePadState currentGamePadState;
        GamePadState previousGamePadState;

        public PlayerIndex controller;

        Texture2D greyBackground;
        Texture2D pauseBox;
        Texture2D howToPlayPic;
        Texture2D pauseResSel;
        Texture2D pauseExitSel;
        Texture2D pauseHowSel;
        Texture2D trialPic;
        Texture2D greySmokePic;
        Rectangle wholescreen;

        Vector2 smokePos;

        int movementLevel;
        int dashSpeedLevel;
        int dashDistanceLevel;
        int playerCoins;
        bool haveDoubleCoin;
        bool haveSlowMo;
        bool haveShield;

        int currentEndlessTime;
        int highscoreEndlessTime;
        int onLevel;

        bool trialMode;
        bool showTrialScreen;

        //Sound Stuff ****************************************
        //1. Create the variable, in the class you want to use it. SoundEffect cash;
        //2. load it in loadcontent   cash = Content.Load<SoundEffect>("cash");
        //3. Play the sound where u want to, (volume 0.0f to 1.0f, 0.0f, 0.0f )  cash.Play(0.8f, 0.0f, 0.0f);
        SoundEffect selectButton;
        SoundEffect selected;

        public GameState()
        {



            //bgLayer1 = new ParallaxBackground();
            //bgLayer1.Initialize(YEngine.Game.Content, "Graphics/cloud(2)", viewPort.Height, -0.5f);
            //obstacleStuff = new Obstacles();    //deleteME
            MessageManager.GetInstance.Init(MessageProc);
            HUD = new AltitudeTimerClass();
            objectManager = new Managers.ObjectManager();
            //objectManager.AddObject(obstacleStuff);
            // set the player to controller 1
            controller = (PlayerIndex)0;
            //pauseScreenMainSelected = new PauseScreenMain();    //howToPlay
            //pauseScreenMainSelected.Initialize();
            //pauseScreenResume = new PauseScreenResume();        //resume
            //pauseScreenResume.Initialize();
            //pauseScreenExit = new PausedScreenExit();           //exit
            //pauseScreenExit.Initialize();

            wholescreen = new Rectangle(0, 0, 1280, 720);
            paused = false;
            howToPlay = false;
            //buff = new ShopState();

        }

        public void Initialize()
        {      
            powerCounter = 0;
            timer = 0.0f;
        }

        public override void LoadContent()
        {
            greyBackground = YEngine.Game.Content.Load<Texture2D>("Graphics/pausegrey");
            pauseBox = YEngine.Game.Content.Load<Texture2D>("Graphics/pausebox");
            howToPlayPic = YEngine.Game.Content.Load<Texture2D>("Graphics/howtoplay");
            pauseResSel = YEngine.Game.Content.Load<Texture2D>("Graphics/pauseResumeSel");
            pauseHowSel = YEngine.Game.Content.Load<Texture2D>("Graphics/pauseHowSel");
            pauseExitSel = YEngine.Game.Content.Load<Texture2D>("Graphics/pauseExitSel");
            cloudArray[0] = YEngine.Game.Content.Load<Texture2D>("Graphics/cloud(2)");
            cloudArray[1] = YEngine.Game.Content.Load<Texture2D>("Graphics/cloud01");
            cloudArray[2] = YEngine.Game.Content.Load<Texture2D>("Graphics/cloud01_small");
            cloudArray[3] = YEngine.Game.Content.Load<Texture2D>("Graphics/cloud02_flip");
            cloudArray[4] = YEngine.Game.Content.Load<Texture2D>("Graphics/cloud02_huechange");
            trialPic = YEngine.Game.Content.Load<Texture2D>("Graphics/trialscreen");
            greySmokePic = YEngine.Game.Content.Load<Texture2D>("Graphics/greyCloud");

            //Sound Stuff ****************************************
            selectButton = YEngine.Game.Content.Load<SoundEffect>("Sounds/SFX_SELECTHIGHLIGHT");
            selected = YEngine.Game.Content.Load<SoundEffect>("Sounds/SFX_BUTTONSELECT");
           

            LoadPercentage = 100.0f;
        }

        public override void OnEnter(string previousState)
        {
            MyLittlePlayer = new Player();
            cityLayer1 = new City();
            MyLittleEnemy = new Enemy();
            objectManager.AddObject(MyLittlePlayer);
            objectManager.AddObject(MyLittleEnemy);
            //viewPort = YEngine.Graphics.ScreenViewport;
            GameManager.GetInstance.LoadLevel(1);
            cityLayer1.Initialize(LevelManager.GetInstance.Background);
            LevelManager.GetInstance.Initialize();
            HUD.Initialize();
            currentEndlessTime = 0;

            smokePos = new Vector2(0, 0);

            Random rand = new Random();
            for (int i = 0; i < 5; i++)
            {
                cloudArrayPos[i].X = rand.Next(-50, 1230);//100;
                cloudArrayPos[i].Y = rand.Next(750, 1800);//730;
                cloudArrayVelo[i] = rand.Next(50, 150);//100; 
            }

#if XBOX
            // get the shop data/read the save file
            if (Global.SaveDevice.FileExists(Global.containerName, Global.fileName_game))
            {
                Global.SaveDevice.Load(
                    Global.containerName,
                    Global.fileName_game,
                    stream =>
                    {
                        using (StreamReader reader = new StreamReader(stream))
                        {
                            movementLevel = int.Parse(reader.ReadLine());
                            dashSpeedLevel = int.Parse(reader.ReadLine());
                            dashDistanceLevel = int.Parse(reader.ReadLine());
                            playerCoins = int.Parse(reader.ReadLine());
                            haveDoubleCoin = bool.Parse(reader.ReadLine());
                            haveSlowMo = bool.Parse(reader.ReadLine());
                            haveShield = bool.Parse(reader.ReadLine());
                        }
                    });
            }
#endif



        }

        public override void OnExit(string nextState)
        {
            objectManager.RemoveAllObjects();
            timer = 0.0f;

#if XBOX
            // make sure the device is ready
            if (Global.SaveDevice.IsReady)
            {
                // save a file asynchronously. this will trigger IsBusy to return true
                // for the duration of the save process.
                Global.SaveDevice.SaveAsync(
                    Global.containerName,
                    Global.fileName_game,
                    stream =>
                    {
                        using (StreamWriter writer = new StreamWriter(stream))
                        {
                            writer.WriteLine(movementLevel);
                            writer.WriteLine(dashSpeedLevel);
                            writer.WriteLine(dashDistanceLevel);
                            writer.WriteLine(playerCoins);
                            writer.WriteLine(haveDoubleCoin);
                            writer.WriteLine(haveSlowMo);
                            writer.WriteLine(haveShield);
                        }
                    });
            }

            // get the highscore data/read the save file
            if (Global.SaveDevice.FileExists(Global.containerName, Global.fileName_Levels))
            {
                Global.SaveDevice.Load(
                    Global.containerName,
                    Global.fileName_Levels,
                    stream =>
                    {
                        using (StreamReader reader = new StreamReader(stream))
                        {
                            highscoreEndlessTime = int.Parse(reader.ReadLine());
                            onLevel = int.Parse(reader.ReadLine());
                        }
                    });
            }

            if (currentEndlessTime > highscoreEndlessTime)
            {
                highscoreEndlessTime = currentEndlessTime;
            }

            //test, remove
            highscoreEndlessTime = 140;

            // make sure the device is ready
            if (Global.SaveDevice.IsReady)
            {
                // save a file asynchronously. this will trigger IsBusy to return true
                // for the duration of the save process.
                Global.SaveDevice.SaveAsync(
                    Global.containerName,
                    Global.fileName_Levels,
                    stream =>
                    {
                        using (StreamWriter writer = new StreamWriter(stream))
                        {
                            writer.WriteLine(highscoreEndlessTime);
                            writer.WriteLine(onLevel);
                        }
                    });
            }
#endif


        }

        public override void Input()
        {
            previousGamePadState = currentGamePadState;

            // Read the current state of the keyboard and gamepad and store it
            currentGamePadState = GamePad.GetState(controller);

            if (howToPlay)
            {
                if (currentGamePadState.Buttons.A == ButtonState.Pressed && previousGamePadState.Buttons.A != ButtonState.Pressed)
                {
                    howToPlay = false;
                    return;
                }
            }

      
               MyLittlePlayer.velocity.X = currentGamePadState.ThumbSticks.Left.X;


                if (YEngine.Input.Keyboard.KeyDown(Keys.D))
                {
                    MyLittlePlayer.velocity.X = 1;
                }

                if (YEngine.Input.Keyboard.KeyDown(Keys.A))
                {
                    MyLittlePlayer.velocity.X = -1;
                }

            if ((currentGamePadState.Buttons.RightShoulder == ButtonState.Pressed || YEngine.Input.Keyboard.KeyPressed(Keys.K)) && MyLittlePlayer.dashRight == false && MyLittlePlayer.dashLeft == false && MyLittlePlayer.snapDown == false && MyLittlePlayer.snapUp == false)
            {
                MyLittlePlayer.dashRight = true;
            }

            if ((currentGamePadState.Buttons.LeftShoulder == ButtonState.Pressed || YEngine.Input.Keyboard.KeyPressed(Keys.J)) && MyLittlePlayer.dashRight == false && MyLittlePlayer.dashLeft == false && MyLittlePlayer.snapDown == false && MyLittlePlayer.snapUp == false)
            {
                MyLittlePlayer.dashLeft = true;
            }

            //no more moving down
            //MyLittlePlayer.velocity.Y = -currentGamePadState.ThumbSticks.Left.Y;

            // snap down and snap up
            if ((currentGamePadState.ThumbSticks.Left.Y >= 0.99 || YEngine.Input.Keyboard.KeyPressed(Keys.W)) && MyLittlePlayer.snapUp == false && MyLittlePlayer.snapDown == false && MyLittlePlayer.position.Y > MyLittlePlayer.upLimit && MyLittlePlayer.dashRight == false && MyLittlePlayer.dashLeft == false)
            {
                MyLittlePlayer.snapUp = true;
            }
            if ((currentGamePadState.ThumbSticks.Left.Y <= -0.99 || YEngine.Input.Keyboard.KeyPressed(Keys.S)) && MyLittlePlayer.snapDown == false && MyLittlePlayer.snapUp == false && MyLittlePlayer.position.Y < MyLittlePlayer.downLimit && MyLittlePlayer.dashRight == false && MyLittlePlayer.dashLeft == false)
            {
                MyLittlePlayer.snapDown = true;
            }

            if (YEngine.Input.Keyboard.KeyPressed(Keys.Escape))
                YEngine.Game.Exit();

            if (YEngine.Input.Keyboard.KeyPressed(Keys.P) || currentGamePadState.Buttons.Start == ButtonState.Pressed  && previousGamePadState.Buttons.Start != ButtonState.Pressed) 
            {
                paused = !paused;
            }

            if (paused)
            {
                if (YEngine.Input.Keyboard.KeyPressed(Keys.Right) || (previousGamePadState.IsButtonUp(Buttons.LeftThumbstickRight) && currentGamePadState.IsButtonDown(Buttons.LeftThumbstickRight)))
                {
                    if (pausedMenu == 3)
                        pausedMenu = 0;
                    selectButton.Play(0.8f, 0.0f, 0.0f);
                    pausedMenu += 1;
                }
                if (YEngine.Input.Keyboard.KeyPressed(Keys.Left) ||( previousGamePadState.IsButtonUp(Buttons.LeftThumbstickLeft) && currentGamePadState.IsButtonDown(Buttons.LeftThumbstickLeft)))
                {
                    if (pausedMenu == 1)
                        pausedMenu = 4;
                    selectButton.Play(0.8f, 0.0f, 0.0f);
                    pausedMenu -= 1;
                }
                if (pausedMenu == 1)
                {
                    if (YEngine.Input.Keyboard.KeyPressed(Keys.Enter) || (currentGamePadState.Buttons.A == ButtonState.Pressed && previousGamePadState.Buttons.A != ButtonState.Pressed))
                    {
                        paused = !paused;
                        selected.Play(0.8f, 0.0f, 0.0f);
                        return;
                    }
                }
                if (pausedMenu == 2)
                {
                    if (YEngine.Input.Keyboard.KeyPressed(Keys.Enter) || (currentGamePadState.Buttons.A == ButtonState.Pressed && previousGamePadState.Buttons.A != ButtonState.Pressed))
                    {
                        howToPlay = true;
                        selected.Play(0.8f, 0.0f, 0.0f);
                        return;
                    }
                }
                if (pausedMenu == 3)
                {
                    if (YEngine.Input.Keyboard.KeyPressed(Keys.Enter) || (currentGamePadState.Buttons.A == ButtonState.Pressed && previousGamePadState.Buttons.A != ButtonState.Pressed))
                    {
                        YEngine.State.ChangeState("MenuState");
                        selected.Play(0.8f, 0.0f, 0.0f);
                        return;   
                    }
                }
            }
        }


        public override void Update()
        {
            if (!paused)
            {
                GC.Collect();
                cityLayer1.Update(YEngine.Time.DeltaTime);
                LevelManager.GetInstance.Update(YEngine.Time.DeltaTime);
                MessageManager.GetInstance.ProcessMessages();
                HUD.Update(YEngine.Time.DeltaTime);
                objectManager.UpdateObjects((float)YEngine.Time.GameTime.ElapsedGameTime.TotalSeconds);
                objectManager.CheckCollisions();


                if (MyLittlePlayer.Alive == false)
                    YEngine.State.ChangeState("GameoverState");

                //if (buff.Sheild == true)
                //{
                //    if (MyLittlePlayer.Alive == false)
                //        buff.Sheild = false;
                //}
                //else if (buff.Sheild == false)
                //{
                //    if (MyLittlePlayer.Alive == false)
                //        YEngine.State.ChangeState("GameoverState");
                //}

                //player on screen for 120 secs.
                timer += YEngine.Time.DeltaTime;
                if (LevelManager.GetInstance.SpeedUpNum != 0 && timer > LevelManager.GetInstance.Length)
                {
                    YEngine.State.ChangeState("GameOverState");
                    return;
                }
                //collide with enemy to Win screen.
                if (LevelManager.GetInstance.SpeedUpNum == 0)
                {
                    YEngine.State.ChangeState("GameOverState");     //winState
                    return;
                }


                if (smokePos.Y > -720)
                {
                    smokePos.Y -= (int)(YEngine.Time.DeltaTime * 500);
                }

                //cloudArrayPos[0].Y -= (int)(YEngine.Time.DeltaTime * cloudArrayVelo[0]);
                Random rand = new Random();
                for (int i = 0; i < 5; i++)
                {
                    cloudArrayPos[i].Y -= (int)(YEngine.Time.DeltaTime * cloudArrayVelo[i]);

                    if (cloudArrayPos[i].Y <= -200)
                    {
                        //cloudArrayPos[i].Y = 900; rand.Next(900, 200);
                        cloudArrayPos[i].X = rand.Next(-50, 1230);//100;
                        cloudArrayPos[i].Y = rand.Next(750, 1800);//730;
                        cloudArrayVelo[i] = rand.Next(50, 150);//100; 

                    }
                }
            }

        }

        public override void Draw()
        {
            YEngine.Graphics.SpriteBatch.Begin();
            cityLayer1.Draw();

            for (int i = 0; i < 5; i++)
            {
                YEngine.Graphics.SpriteBatch.Draw(cloudArray[i], cloudArrayPos[i], Color.White);
            }

            objectManager.DrawObjects(YEngine.Graphics.SpriteBatch);
            HUD.Draw();

            if (smokePos.Y > -720)
            {
                YEngine.Graphics.SpriteBatch.Draw(greySmokePic, smokePos, Color.White);
            }

            if (paused)
            {
                YEngine.Graphics.SpriteBatch.Draw(greyBackground, wholescreen, Color.White);
                YEngine.Graphics.SpriteBatch.Draw(pauseBox, wholescreen, Color.White);
                if (pausedMenu == 1)
                {
                    YEngine.Graphics.SpriteBatch.Draw(pauseResSel, wholescreen, Color.White);
                }
                //pauseScreenMainSelected.Draw();     //HowToPlay
                else if (pausedMenu == 2)
                {
                    YEngine.Graphics.SpriteBatch.Draw(pauseHowSel, wholescreen, Color.White);
                }
                //pauseScreenResume.Draw();           //REsume
                else if (pausedMenu == 3)
                {
                    YEngine.Graphics.SpriteBatch.Draw(pauseExitSel, wholescreen, Color.White);
                }
                //pauseScreenExit.Draw();             //exit
                if (howToPlay)
                {
                    //DRAW IMAGE HERE!
                    YEngine.Graphics.SpriteBatch.Draw(howToPlayPic, wholescreen, Color.White);
                    //howToPlay = !howToPlay;
                }

            } 


            // draw collision rects
            Texture2D dummyTexture;
            Rectangle dummyRectangle;
            dummyRectangle = MyLittlePlayer.ColRect;
            dummyTexture = new Texture2D(YEngine.Game.GraphicsDevice, 1, 1);
            dummyTexture.SetData(new Color[] { Color.White });

            //YEngine.Graphics.SpriteBatch.Draw(dummyTexture, dummyRectangle, Color.White);

            YEngine.Graphics.SpriteBatch.End();
        }

        public void MessageProc(Messages.Message msg)
        {
            // fuck c# switches
            if( msg.MsgID == Messages.MSG_TYPE.Msg_CreateBox )
            {
                Obstacles newOb = new Obstacles();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/crate01"), msg.X, msg.Y, 0, 150);
                newOb.ObjectID = Object_Type.OBSTACLES;
                newOb.ObstacleID = Obstacle_Type.CRATE;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateWing)
            {
                Obstacles newOb = new Obstacles();
                Random rand = new Random();
                int b = rand.Next(2);
                if( b == 0 )
                    newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/BrokenAirplaneWing"), msg.X, msg.Y, 0, 100);
                else
                    newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/BrokenAirplaneWing_Rev"), msg.X, msg.Y, 0, 100);
                newOb.ObjectID = Object_Type.OBSTACLES;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateBalloon)
            {
                PowerUp newOb = new PowerUp();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/balloon"), msg.X, msg.Y, 0, -100);
                newOb.ObjectID = Object_Type.POWERUP;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateGoldBalloon)                                                           //Gold Balloon
            {
                PowerUp newOb = new PowerUp();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/BalloonGold"), msg.X, msg.Y, 0, -200);
                newOb.ObjectID = Object_Type.CURRENCY;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreatePropeller)
            {
                Obstacles newOb = new Obstacles();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/Propeller"), msg.X, msg.Y, 0, 200);
                newOb.ObjectID = Object_Type.OBSTACLES;
                newOb.ObstacleID = Obstacle_Type.PROP;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateBirds)
            {
                Birds newOb = new Birds();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/birdsani"), msg.X, msg.Y, 150, 0);
                newOb.ObjectID = Object_Type.BIRDS;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateCoin)
            {
                Coins newOb = new Coins();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/Coin"), msg.X, msg.Y, 200, 200);
                newOb.ObjectID = Object_Type.COINS;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateSeat)
            {
                Obstacles newOb = new Obstacles();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/AirplaneSeat"), msg.X, msg.Y, 0, 150);
                newOb.ObjectID = Object_Type.OBSTACLES;
                newOb.ObstacleID = Obstacle_Type.SEAT;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateExit)
            {
                Obstacles newOb = new Obstacles();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/EmergencyExit"), msg.X, msg.Y, 0, 170);
                newOb.ObjectID = Object_Type.OBSTACLES;
                newOb.ObstacleID = Obstacle_Type.CRATE;
                objectManager.AddObject(newOb);
            }

            if (msg.MsgID == Messages.MSG_TYPE.Msg_CreateEngine)
            {
                Obstacles newOb = new Obstacles();
                newOb.Initialize(YEngine.Game.Content.Load<Texture2D>("Graphics/Engine"), msg.X, msg.Y, 0, 175);
                newOb.ObjectID = Object_Type.OBSTACLES;
                newOb.ObstacleID = Obstacle_Type.CRATE;
                objectManager.AddObject(newOb);
            }
        }
    }
}
